package org.naxx.security.naxxlet;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;

import org.apache.log4j.Logger;
import org.naxx.security.util.FileSystemUtil;
import org.naxx.security.util.Util;

/**
 * Performance again, we do that later.
 */
public final class NaxxClassLoader extends ClassLoader {
	
	private static final Logger logger = Logger.getLogger(NaxxClassLoader.class);

	private final String naxxletsDirectory;
	
	public NaxxClassLoader(String naxxletsDirectory) {
		this.naxxletsDirectory = naxxletsDirectory;
	}

	public Class<?> findClass(String binaryClassName) {
        byte[] b = this.loadClassDataFromNaxxlets(this.getClassNameOnly(binaryClassName));
        return defineClass(binaryClassName, b, 0, b.length);
    }

//	@Deprecated
//    private byte[] loadClassData(String binaryClassName) {
//    	String fileName = binaryClassName.substring(binaryClassName.lastIndexOf('.')+1, 
//    			binaryClassName.length());
//    	
//    	return FileSystemUtil.getFileBytes(this.naxxletsDirectory + File.separatorChar 
//    			+ fileName + ".class");
//    }
    
    private byte[] loadClassDataFromNaxxlets(String className) {
    	File[] naxxlets = new File(this.naxxletsDirectory).listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				return pathname.isDirectory();
			}
    	});
    	logger.info("Found '" + naxxlets.length + "' naxxlets in repository: ");
    	logger.info(Util.format(FileSystemUtil.filesToStrings(naxxlets)));
    	
    	for (int i = 0; i < naxxlets.length; i++) {
			File[] files = naxxlets[i].listFiles(new FilenameFilter(){
				public boolean accept(File dir, String name) {
					return name.endsWith(".class");
				}
			});
			File classFile = this.findMatch(files, className);
			if(classFile != null) {
				return FileSystemUtil.getFileBytes(classFile.getAbsolutePath());
			}
		}
    	logger.warn("Class '" + className + "' could not be found in repository");
    	return null;
    }
    
    private String getClassNameOnly(String binaryClassName) {
    	return binaryClassName.substring(binaryClassName.lastIndexOf('.') + 1);
    }

    private File findMatch(File[] naxxletFiles, String className) {
    	for (int i = 0; i < naxxletFiles.length; i++) {
			if(naxxletFiles[i].getName().equals(className)) {
				return naxxletFiles[i];
			}
		}
    	return null;
    }
}
